package murgtug.mediamanager.server.service;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.servlet.ServletException;

import murgtug.mediamanager.shared.model.Album;
import murgtug.mediamanager.shared.model.Artist;
import murgtug.mediamanager.shared.model.Song;
import murgtug.mediamanager.shared.service.AudioService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class AudioServiceImpl extends RemoteServiceServlet implements AudioService {

	private static final long serialVersionUID = 1L;

	protected File mediaBaseDir;
	
	private static FileFilter IS_DIRECTORY_FILTER = new FileFilter() {
		
		@Override
		public boolean accept(File pathname) {
			return pathname.isDirectory();
		}
	};
	
	private static FileFilter IS_FILE_FILTER = new FileFilter() {
		
		@Override
		public boolean accept(File pathname) {
			return pathname.isFile();
		}
	};
	
	@Override
	public void init() throws ServletException {
		String baseDirPathname = getServletConfig().getInitParameter("media-basedir");
		if (baseDirPathname == null) {
			throw new RuntimeException("Missing 'media-basedir' servlet parameter'");
		} else {
			mediaBaseDir = new File(baseDirPathname);
		}
	}
	
	public static int getFileId(File file) {
		return file.getName().hashCode();
	}
	
	@Override
	public List<Artist> getArtists() {
		
		File[] files = mediaBaseDir.listFiles(IS_DIRECTORY_FILTER);
		
		List<Artist> artists = new ArrayList<Artist>(files.length);
		
		for (File file: files) {
			
			if (file.isDirectory()) {
				
			    int id = getFileId(file);

			    Artist artist = new Artist();
			    artist.setId(id);
				artist.setName(file.getName());
					
				artists.add(artist);
			}
		}
		
		Collections.sort(artists, new Comparator<Artist>() {

			@Override
			public int compare(Artist o1, Artist o2) {
				return o1.getName().compareTo(o2.getName());
			}
			
		});
		
		return artists;
	}

	@Override
	public List<Album> getArtistAlbums(int artistId) {
		
		File artistBaseDir = findArtistBaseDir(mediaBaseDir, artistId);
		if (artistBaseDir == null) {
			return new ArrayList<Album>(0);
		}
		
		File[] files = artistBaseDir.listFiles(IS_DIRECTORY_FILTER);
		
		Artist artist = new Artist();
		artist.setId(artistId);
		artist.setName(artistBaseDir.getName());
		
		List<Album> albums = new ArrayList<Album>(files.length);
		
		for (File file: files) {
			
			if (file.isDirectory()) {
				
				int id = getFileId(file);
				
				Album album = new Album();
				album.setId(id);
				album.setName(file.getName());
				album.setArtist(artist);
				
				albums.add(album);
			}
		}

		Collections.sort(albums, new Comparator<Album>() {

			@Override
			public int compare(Album o1, Album o2) {
				return o1.getName().compareTo(o2.getName());
			}
		});
		
		return albums;
	}

	public static File findArtistBaseDir(File mediaBaseDir, int artistId) {
		
		File[] files = mediaBaseDir.listFiles(IS_DIRECTORY_FILTER);
		
		for (File file: files) {
			
			if (getFileId(file) == artistId) {
				return file;
			}
			
		}

		return null;
	}

	@Override
	public List<Song> getAlbumSongs(int artistId, int albumId) {
		
		File artistBaseDir = findArtistBaseDir(mediaBaseDir, artistId);
		if (artistBaseDir == null) {
			return new ArrayList<Song>(0);
		}
		
		Artist artist = new Artist();
		artist.setId(artistId);
		artist.setName(artistBaseDir.getName());
		
		File albumBaseDir = findAlbumBaseDir(artistBaseDir, albumId);
		if (albumBaseDir == null) {
			return new ArrayList<Song>(0);
		}
		
		Album album = new Album();
		album.setId(albumId);
		album.setArtist(artist);
		album.setName(albumBaseDir.getName());
		
		File[] files = albumBaseDir.listFiles(IS_FILE_FILTER);
		
		List<Song> songs = new ArrayList<Song>(files.length);
		
		for (File file: files) {
			
			int id = getFileId(file);

			Song song = new Song();
			song.setId(id);
			song.setTrackNr(Integer.parseInt(file.getName().substring(0, 2), 10));
			song.setTitle(file.getName().substring(3));
			song.setAlbum(album);
			
			songs.add(song);
		}
		
		Collections.sort(songs, new Comparator<Song>() {

			@Override
			public int compare(Song o1, Song o2) {
				return Integer.valueOf(o1.getTrackNr()).
					compareTo(Integer.valueOf(o2.getTrackNr()));
			}
		});
		
		return songs;
	}

	public static File findAlbumBaseDir(File artistBaseDir, int albumId) {
		
		File[] files = artistBaseDir.listFiles(IS_DIRECTORY_FILTER);
		
		for (File file: files) {
			
			if (getFileId(file) == albumId) {
				return file;
			}
		}

		return null;
	}

	public static File findSongFile(File albumBaseDir, int songId) {
		
		File[] files = albumBaseDir.listFiles(AudioServiceImpl.IS_FILE_FILTER);
		
		for (File file: files) {
			
			int id = AudioServiceImpl.getFileId(file);
			if (id == songId) {
				return file;
			}
		}
		
		return null;
	}
	
}
